#include "Values.h"


Value::Value()
    :value_type(VALUE_TYPE_NULL), value_int(0), value_uint(0), value_double(0.0),  value_str(""), value_uchar(0)
{}

Value::~Value()
{
}

void Value::Clear()
{
    if (value_type == VALUE_TYPE_ARRAY)
    {
        value_array.clear();
    }

    value_type = VALUE_TYPE_NULL;
}

Value::Value(int value, unsigned int bytes)
    :value_bytes(bytes)
{
    value_int = value;
    value_type = VALUE_TYPE_INT;
}

Value::Value(short value)
    :value_bytes(2)
{
    value_int = value;
    value_type = VALUE_TYPE_SHORT;
}

Value::Value(unsigned int value, unsigned int bytes)
    :value_bytes(bytes)
{
    value_uint = value;
    value_type = VALUE_TYPE_UINT;
}

Value::Value(unsigned short value)
    :value_bytes(2)
{
    value_uint = value;
    value_type = VALUE_TYPE_USHORT;
}

Value::Value(double value)
    :value_bytes(4)
{
    value_double = value;
    value_type = VALUE_TYPE_DOUBLE;
}

Value::Value(const std::string& value)
{
    value_str = value;
    value_bytes = value.size();
    value_type = VALUE_TYPE_STR;
}

Value::Value(unsigned char value)
    :value_bytes(1)
{
    value_uchar = value;
    value_type = VALUE_TYPE_UCHAR;
}

Value & Value::operator=(int value)
{
    value_int = value;
    value_type = VALUE_TYPE_INT;
    return *this;
}

Value & Value::operator=(unsigned int value)
{
    value_uint = value;
    value_type = VALUE_TYPE_UINT;
    return *this;
}

Value & Value::operator=(double value)
{
    value_double = value;
    value_type = VALUE_TYPE_DOUBLE;
    return *this;
}

Value & Value::operator=(const std::string& value)
{
    value_str = value;
    value_type = VALUE_TYPE_STR;
    return *this;
}

Value & Value::operator=(unsigned char value)
{
    value_uchar = value;
    value_type = VALUE_TYPE_UCHAR;
    return *this;
}

Value & Value::operator=(const Value&other)
{
    value_type = other.value_type;
    value_int = other.value_int;
    value_double = other.value_double;
    value_str = other.value_str;
    value_uchar = other.value_uchar;
    value_uint = other.value_uint;
    value_bytes = other.value_bytes;

    if (other.value_type == VALUE_TYPE_ARRAY)
    {
        for (size_t i = 0; i < other.value_array.size(); ++i)
        {
            std::shared_ptr<Value> val(new Value());
            val->value_type = other.value_array[i]->value_type;
            val->value_int = other.value_array[i]->value_int;
            val->value_uint = other.value_array[i]->value_uint;
            val->value_double = other.value_array[i]->value_double;
            val->value_str = other.value_array[i]->value_str;
            val->value_uchar = other.value_array[i]->value_uchar;
            val->value_bytes = other.value_array[i]->value_bytes;

            value_array.push_back(val);
        }
    }

    return *this;
}

std::string Value::to_data() const
{
    std::string ret_val = "";
    switch (value_type)
    {
    case VALUE_TYPE_SHORT:
    case VALUE_TYPE_USHORT:
    {
        unsigned short data = (unsigned short)to_int();
        char * pData = (char*)&data;

        for (unsigned int i = 0; i < value_bytes; ++i)
        {
            ret_val.append((char *)&pData[value_bytes - 1 - i], 1);
        }
    }
        break;
    case VALUE_TYPE_INT:
    case VALUE_TYPE_UINT:
    {
        unsigned int data = (unsigned int)to_int();
        char * pData = (char*)&data;
        for (unsigned int i = 0; i < value_bytes; ++i)
        {
            ret_val.append((char *)&pData[value_bytes - 1 - i], 1);
        }
    }
        break;
    case VALUE_TYPE_UCHAR:
    {
        unsigned char val = to_byte();
        ret_val.append((char *)&val, 1);
    }
        break;
    case VALUE_TYPE_STR:
        ret_val = value_str;
        break;
    case VALUE_TYPE_ARRAY:
    {
        for (unsigned int i = 0; i < size(); ++i)
        {
            ret_val += value_array[i]->to_data();
        }
    }
        break;
    default:
        return "";
    }

    return ret_val;
}

std::string Value::to_str() const
{
    switch (value_type)
    {
    case VALUE_TYPE_DOUBLE:
    {
        std::stringstream s;
        s << value_double;
        return s.str();
    }
    break;
    case VALUE_TYPE_SHORT:
    case VALUE_TYPE_INT:
    {
        std::stringstream s;
        s << value_int;
        return s.str();
    }
    break;
    case VALUE_TYPE_USHORT:
    case VALUE_TYPE_UINT:
    {
        std::stringstream s;
        s << value_uint;
        return s.str();
    }
    break;
    case VALUE_TYPE_UCHAR:
    {
        std::stringstream s;
        s << value_uchar;
        return s.str();
    }
    break;
    default:
        return value_str;
    }
}

int Value::to_int() const
{
    switch (value_type)
    {
    case VALUE_TYPE_SHORT:
    case VALUE_TYPE_INT:
        return value_int;
    case VALUE_TYPE_USHORT:
    case VALUE_TYPE_UINT:
        return (int)value_uint;
    default:
        return 0;
    }
}

unsigned int Value::to_uint() const
{
    switch (value_type)
    {
    case VALUE_TYPE_USHORT:
    case VALUE_TYPE_UINT:
        return value_uint;
    case VALUE_TYPE_SHORT:
    case VALUE_TYPE_INT:
        return (unsigned int)value_int;
    default:
        return 0;
    }
}

double Value::to_double() const
{
    switch (value_type)
    {
    case VALUE_TYPE_DOUBLE:
        return value_double;
    default:
        return 0.0;
    }
}

unsigned char Value::to_byte() const
{
    switch (value_type)
    {
    case VALUE_TYPE_UCHAR:
        return value_uchar;
    default:
        return 0;
    }
}

void Value::push_back(Value value)
{
    value_type = VALUE_TYPE_ARRAY;

    std::shared_ptr<Value> val(new Value());
    val->value_type = value.value_type;
    val->value_int = value.value_int;
    val->value_double = value.value_double;
    val->value_str = value.value_str;
    val->value_uchar = value.value_uchar;
    val->value_uint = value.value_uint;
    val->value_bytes = value.value_bytes;

    value_array.push_back(val);
}

const Value Value::operator[](unsigned int index)
{
    if (value_type == VALUE_TYPE_ARRAY)
    {
        if (value_array.size() > index)
        {
            return *(value_array[index]);
        }
    }

    return Value();
}

unsigned int Value::size() const
{
    if (value_type == VALUE_TYPE_ARRAY)
    {
        return value_array.size();
    }
    else
    {
        return 1;
    }
}

VALUE_TYPE Value::type()
{
    return value_type;
}

unsigned int Value::bytes()
{
    return value_bytes;
}